/*
 Copyright (c) 2009 by contributors:

 * James Hight (http://labs.zavoo.com/)
 * Richard R. Masters

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/


package org.svgweb.utils;
import flash.system.Capabilities;
    using StringTools;
	
    class SVGUnits
     {
public static var UNKNOWN:Int = 0;
        public static var USER:Int = 1; /* User coordinates */
        // CSS Unit Types
        public static var EM:Int = 2;
        public static var EX:Int = 3;
        public static var PX:Int = 4;
        public static var PT:Int = 5;
        public static var PC:Int = 6;
        public static var CM:Int = 7;
        public static var MM:Int = 8;
        public static var IN:Int = 9;
        public static var PERCENT:Int = 10; /* Relative percentage; ex:50% */
        
        /**
         * Determines the type of unit given, such as pixels, points, ems, etc.
         *
         * @param String to check for unit type.
         * 
         * @returns Null if none if the available types, otherwise returns one
         * of the static constants on this class such as SVGUnits.PX, SVGUnits.PT,
         * etc.        
         **/
        public static function getType(unit:Dynamic):Int {
            if (unit == null ||  unit == '') {
                return UNKNOWN;
            }
            
            // FIXME:Handle negative values; the spec says implementations
            // don't have to handle them but should convert them into a usable
            // form
            if (~/em\s*_S_/.match(unit)) {
                return SVGUnits.EM;
            } else if (~/ex\s*$/.match(unit)) {
                return SVGUnits.EX;
            } else if (~/px\s*$/.match(unit)) {
                return SVGUnits.PX;
            } else if (~/pt\s*$/.match(unit)) {
                return SVGUnits.PT;
            } else if (~/pc\s*$/.match(unit)) {
                return SVGUnits.PC;
            } else if (~/cm\s*$/.match(unit)) {
                return SVGUnits.CM;
            } else if (~/mm\s*$/.match(unit)) {
                return SVGUnits.MM;
            } else if (~/in\s*$/.match(unit)) {
                return SVGUnits.IN;
            } else if (~/^\s*[0-9]+\s*$/.match(unit)) {
                return SVGUnits.USER;
            } else if (~/^\s*[0-9]+%\s*$/.match(unit)) {
                return SVGUnits.PERCENT;
            } else {
                return UNKNOWN;
            }
        }
        
        /**
         * Converts a given point value to it's pixel equivalent.
         * 
         * @param Numeric point value to be converted.
         * 
         * @return Numeric pixel value.
         **/
        public static function pointsToPixels(num:Float):Float {
            return num * (Capabilities.screenDPI / 72);
        }
        
        
        // Convert number to seconds
        public static function parseTimeVal(timeVal:String):Float {
            if (timeVal.indexOf("ms") != -1) {
                return SVGUnits.parseNum(timeVal) / 1000;
            }
            else {
                return SVGUnits.parseNum(timeVal);
            }
        }
        
        /**
         * Object of colors by name
         **/
        public static var colors:Dynamic = {
            blue:0x0000ff,
            green:0x008000,
            red:0xff0000,
            aliceblue:0xf0f8ff,
            antiquewhite:0xfaebd7,
            aqua:0x00ffff,
            aquamarine:0x7fffd4,
            azure:0xf0ffff,
            beige:0xf5f5dc,
            bisque:0xffe4c4,
            black:0x000000,
            blanchedalmond:0xffebcd,
            blueviolet:0x8a2be2,
            brown:0xa52a2a,
            burlywood :0xdeb887,
            cadetblue :0x5f9ea0,
            chartreuse :0x7fff00,
            chocolate :0xd2691e,
            coral:0xff7f50,
            cornflowerblue :0x6495ed,
            cornsilk :0xfff8dc,
            crimson :0xdc143c,
            cyan :0x00ffff,
            darkblue :0x00008b,
            darkcyan :0x008b8b,
            darkgoldenrod :0xb8860b,
            darkgray :0xa9a9a9,
            darkgreen :0x006400,
            darkgrey :0xa9a9a9,
            darkkhaki :0xbdb76b,
            darkmagenta :0x8b008b,
            darkolivegreen :0x556b2f,
            darkorange :0xff8c00,
            darkorchid :0x9932cc,
            darkred :0x8b0000,
            darksalmon :0xe9967a,
            darkseagreen :0x8fbc8f,
            darkslateblue :0x483d8b,
            darkslategray :0x2f4f4f,
            darkslategrey :0x2f4f4f,
            darkturquoise :0x00ced1,
            darkviolet :0x9400d3,
            deeppink :0xff1493,
            deepskyblue :0x00bfff,
            dimgray :0x696969,
            dimgrey :0x696969,
            dodgerblue :0x1e90ff,
            firebrick :0xb22222,
            floralwhite :0xfffaf0,
            forestgreen :0x228b22,
            fuchsia :0xff00ff,
            gainsboro :0xdcdcdc,
            ghostwhite :0xf8f8ff,
            gold :0xffd700,
            goldenrod :0xdaa520,
            gray :0x808080,
            grey :0x808080,
            greenyellow :0xadff2f,
            honeydew :0xf0fff0,
            hotpink :0xff69b4,
            indianred :0xcd5c5c,
            indigo :0x4b0082,
            ivory :0xfffff0,
            khaki :0xf0e68c,
            lavender :0xe6e6fa,
            lavenderblush :0xfff0f5,
            lawngreen :0x7cfc00,
            lemonchiffon :0xfffacd,
            lightblue :0xadd8e6,
            lightcoral :0xf08080,
            lightcyan :0xe0ffff,
            lightgoldenrodyellow :0xfafad2,
            lightgray :0xd3d3d3,
            lightgreen :0x90ee90,
            lightgrey :0xd3d3d3,
            lightpink :0xffb6c1,
            lightsalmon :0xffa07a,
            lightseagreen :0x20b2aa,
            lightskyblue :0x87cefa,
            lightslategray :0x778899,
            lightslategrey :0x778899,
            lightsteelblue :0xb0c4de,
            lightyellow :0xffffe0,
            lime :0x00ff00,
            limegreen :0x32cd32,
            linen :0xfaf0e6,
            magenta :0xff00ff,
            maroon :0x800000,
            mediumaquamarine :0x66cdaa,
            mediumblue :0x0000cd,
            mediumorchid :0xba55d3,
            mediumpurple :0x9370db,
            mediumseagreen :0x3cb371,
            mediumslateblue :0x7b68ee,
            mediumspringgreen :0x00fa9a,
            mediumturquoise :0x48d1cc,
            mediumvioletred :0xc71585,
            midnightblue :0x191970,
            mintcream :0xf5fffa,
            mistyrose :0xffe4e1,
            moccasin :0xffe4b5,
            navajowhite :0xffdead,
            navy :0x000080,
            oldlace :0xfdf5e6,
            olive :0x808000,
            olivedrab :0x6b8e23,
            orange :0xffa500,
            orangered :0xff4500,
            orchid :0xda70d6,
            palegoldenrod :0xeee8aa,
            palegreen :0x98fb98,
            paleturquoise :0xafeeee,
            palevioletred :0xdb7093,
            papayawhip :0xffefd5,
            peachpuff :0xffdab9,
            peru :0xcd853f,
            pink :0xffc0cb,
            plum :0xdda0dd,
            powderblue :0xb0e0e6,
            purple :0x800080,
            rosybrown :0xbc8f8f,
            royalblue :0x4169e1,
            saddlebrown :0x8b4513,
            salmon :0xfa8072,
            sandybrown :0xf4a460,
            seagreen :0x2e8b57,
            seashell :0xfff5ee,
            sienna :0xa0522d,
            silver :0xc0c0c0,
            skyblue :0x87ceeb,
            slateblue :0x6a5acd,
            slategray :0x708090,
            slategrey :0x708090,
            snow :0xfffafa,
            springgreen :0x00ff7f,
            steelblue :0x4682b4,
            tan :0xd2b48c,
            teal :0x008080,
            thistle :0xd8bfd8,
            tomato :0xff6347,
            turquoise :0x40e0d0,
            violet :0xee82ee,
            wheat :0xf5deb3,
            white :0xffffff,
            whitesmoke :0xf5f5f5,    
            yellow :0xffff00,
            yellowgreen :0x9acd32,
		};
        
        public static function rgbToNumber (r:UInt, g:UInt, b:UInt):UInt {
            return (r << 16) | (g << 8) | (b);
        }
        
        /**
         * Get the number value of a color string
         * 
         * @param color String value of a color ('black', '#ff0000', etc...)
         * 
         * @return  [ Numeric value of color , opacity ]
         **/
        public static function getColor(color:String):UInt {
            var r:Int = 0;
            var g:Int = 0;
            var b:Int = 0;

            if (color != null) {            
                color = ~/ /g.replace(color, "");
                if( ~/^#/.match(color)) {
                    // #456 is short for #445566
                    if (color.length == 4) {
                        var rval:String, gval:String, bval:String;
                        rval = color.substr(1,1) + color.substr(1,1);
                        gval = color.substr(2,1) + color.substr(2,1);
                        bval = color.substr(3,1) + color.substr(3,1);
                        color = "#" + rval + gval + bval;
                    }
                    color = color.replace('#', '0x');
                    return Std.parseInt(color);
                }
                else if ( (color.indexOf("rgb") != -1) || color.indexOf("RGB") != -1) {
                    var str:Array<Dynamic> = ~/\s|rgb\(|\)/gi.replace(color, "").split(",");
                    if (str[0].match(~/%/)) {
                        str[0]=str[0].replace(~/%/g, "");
                        r = str[0];
                        r =  Math.round(r * 255 / 100);
                    }
                    else {
                           r = str[0];
                    }
                    if (str[1].match(~/%/)) {
                        str[1]=str[1].replace(~/%/g, "");
                        g = str[1];
                        g = Math.round(g * 255 / 100);
                    }
                    else {
                           g = str[1];
                    }
                    if (str[2].match(~/%/)) {
                        str[2]=str[2].replace(~/%/g, "");
                        b = str[2];
                        b = Math.round(b * 255 / 100);
                    }
                    else {
                        b = str[2];
                    }
                    return rgbToNumber(r, g, b);
                   
                }
                else if (colors.hasOwnProperty(color)) {
                    return Reflect.field(colors, color);
                }
                else {
                    return Std.parseInt(color);
                }
            }            
            return 0x000000;
        }
        public static function getColorAndAlpha(color:String):Array<Dynamic> {
            var r:Int = 0;
            var g:Int = 0;
            var b:Int = 0;
            var a:Float = 0.0;
            var str:Array<Dynamic>;

            if (color != null) {
                color=~/\s/g.replace(color, "");
                if(~/^#/.match(color)) {
                    // #456 is short for #445566
                    if (color.length == 4) {
                        var rval:String, gval:String, bval:String;
                        rval = color.substr(1,1) + color.substr(1,1);
                        gval = color.substr(2,1) + color.substr(2,1);
                        bval = color.substr(3,1) + color.substr(3,1);
                        color = "#" + rval + gval + bval;
                    }
                    color = color.replace('#', '0x');
                    return [ Std.parseInt(color), 1.0 ];
                }
                else if(color.indexOf("rgba") != -1) {
                    str = ~/\s|rgba\(|\)/g.replace(color, "").split(",");
                    if (str[0].match(~/%/)) {
                        str[0]=str[0].replace(~/%/g, "");
                        r = str[0];
                        r = Math.round(r * 255 / 100);
                    }
                    else {
                           r = str[0];
                    }
                    if (str[1].match(~/%/)) {
                        str[1]=str[1].replace(~/%/g, "");
                        g = str[1];
                        g = Math.round(g * 255 / 100);
                    }
                    else {
                           g = str[1];
                    }
                    if (str[2].match(~/%/)) {
                        str[2]=str[2].replace(~/%/g, "");
                        b = str[2];
                        b = Math.round(b * 255 / 100);
                    }
                    else {
                        b = str[2];
                    }
                    if (str[3].match(~/%/)) {
                        str[3]=str[3].replace(~/%/g, "");
                        a = str[3];
                        a = a / 100.0;
                    }
                    else {
                        a = str[3];
                    }
                    return [ rgbToNumber(r, g, b), a ];
                   
                }
                else if(color.indexOf("rgb") != -1) {
                    str = ~/\s|rgb\(|\)/g.replace(color, "").split(",");
                    if (str[0].match(~/%/)) {
                        str[0]=str[0].replace(~/%/g, "");
                        r = str[0];
                        r = Math.round(r * 255 / 100);
                    }
                    else {
                           r = str[0];
                    }
                    if (str[1].match(~/%/)) {
                        str[1]=str[1].replace(~/%/g, "");
                        g = str[1];
                        g = Math.round(g * 255 / 100);
                    }
                    else {
                           g = str[1];
                    }
                    if (str[2].match(~/%/)) {
                        str[2]=str[2].replace(~/%/g, "");
                        b = str[2];
                        b = Math.round(b * 255 / 100);
                    }
                    else {
                        b = str[2];
                    }
                    return [ rgbToNumber(r, g, b), 1.0 ];
                   
                }
                else if (colors.hasOwnProperty(color)) {
                    return [ Reflect.field(colors, color), 1.0 ];
                }
                else {
                    return [ Std.parseInt(color), 1.0 ];
                }
            }            
            return [ 0x000000, 0.0 ];
        }
                
        /**
         * Remove the numeric value of string will all characters removed except '0-9', '.', and '-'
         * 
         * @param String to be cleaned
         * 
         * @return Numeric value of string will all characters removed except '0-9', '.', and '-'
         **/
        public static function parseNum(num:Dynamic):Float {
            if (num == null) {
                return 0;
            }
            var numString:String = Std.string(num);
            if (isColor(numString)) {
                return SVGUnits.getColor(numString);
            }
            numString = ~/[^0-9\.\-eE]+/sig.replace(numString, '');
			//trace(num + '->' + numString);
            return Std.parseFloat(numString);
        }

        public static function isColor(colorString:String):Bool {
            if (  ~/^#/.match(colorString)
                || (colorString.indexOf("rgb") != -1)
                || (colors.hasOwnProperty(colorString)) ) {
                return true;
            }
            else {
                return false;
            }
        }

        // the second parameter is the maximum value to be used for percent values
        public static function parseNumPct(numParam:Dynamic, max:Float):Float {
            var numString:String = Std.string(numParam);
			//trace(numString);
            if (~/%/.match(numString)) {
                numString=~/%/g.replace(numString, "");
                var num:Float = SVGUnits.parseNum(numString);
                num = num * max / 100;
                return num;
            }
            else {
                return SVGUnits.parseNum(numString);
            }
        }
        
        public static function trim(string:String):String {
            if (null != string) {
                return ~/\s+$/s.replace(~/^\s+/s.replace(string, ''), '');            
                //return ~/\s+_S_/s.replace(~/^\s+/s.replace(string, ''), '');            
            }
            return string;        
        }

        // convert a number into a color string value
        public static function colorString(colorVal:Int):String {
            return  '#' + colorVal.hex(6);
        }

        public static function addColors(a:Float, b:Float):Float {
            var aR:UInt = Std.int(a) >> 16;
            var aG:UInt = ( Std.int(a) >> 8 ) & 0xff;
            var aB:UInt = Std.int(a) & 0xff;

            var bR:UInt = Std.int(Math.min(aR + ( (Std.int(b) >> 16) & 0xff), 0xff));
            var bG:UInt = Std.int(Math.min(aG + ( (Std.int(b) >> 8 ) & 0xff), 0xff));
            var bB:UInt = Std.int(Math.min(aB + (Std.int(b) & 0xff), 0xff));
            return (bR << 16) | (bG << 8) | bB;
        }

    }
